<?php


namespace App\Repositories;


use Illuminate\Support\Facades\DB;
use App\Exceptions\BasicException;
use Illuminate\Support\Facades\Route;

class AccessRepository
{
    /**
     * 获取未录入数据库或者数据库存在但路由文件中不存在的路由
     * @param int $type 类型，1：未录入数据库；2：数据库存在但路由文件中不存在
     * @return array
     */
    public function getNoEntryOrNoExistRoute($type = 1)
    {
        //最新路由（web.php中的）
        $latestRoutes = $this->getSystemRoutes();
        $latestRouteUriMethods = array_column($latestRoutes, 'uri_method');

        //已录入数据库的路由
        $dbRouteUriMethods = app('model_route')
            ->select('id', DB::raw("CONCAT_WS(':', uri, method) as uri_method"))
            ->pluck('uri_method', 'id')->toArray();

        if ($type == 1) {
            $noEntryUriMethods = array_diff($latestRouteUriMethods, $dbRouteUriMethods);
            $noEntryRoutes = [];
            foreach (array_keys($noEntryUriMethods) as $i) {
                unset($latestRoutes[$i]['uri_method']);
                $noEntryRoutes[] = $latestRoutes[$i];
            }
            return $noEntryRoutes;
        } else {
            return array_keys(array_diff($dbRouteUriMethods, $latestRouteUriMethods));
        }
    }

    /**
     * @param string|array $middleware 获取目标中间件下包含的路由，多个传数组表示同时包含
     * @return array
     */
    public function getSystemRoutes($middleware = 'api')
    {
        $routes = Route::getRoutes();

        $formatRoutes = [];
        foreach ($routes as $route) {

            $uri = $route['uri'];
            $i = strpos($uri, '{');
            if ($i !== false) {
                $uri = substr($uri, 0, $i) . '*';
            }

            $method = $route['method'];
            $actionInfo = $route['action'];

            if (!isset($actionInfo['middleware']) || $method == 'OPTIONS') {
                continue;
            }
            if ($middleware) {
                if (is_array($middleware)) {
                    if (array_diff($middleware, $actionInfo['middleware']) == []) {
                        continue;
                    }
                } else {
                    if (!in_array($middleware, $actionInfo['middleware'])) {
                        continue;
                    }
                }
            }

            $uses = $actionInfo['uses'];
            $uses = str_replace('App\Http\Controllers\Admin', '', $uses);
            $index = strrpos($uses, '\\');
            $ctrDir = substr($uses, 0, $index);
            $ctrAct = substr($uses, $index + 1);
            [$controller, $action] = explode('@', $ctrAct);

             $formatRoute = [
               'ctr_dir' => trim($ctrDir, '\\'), //控制器所在目录，从App\Http\Controllers\Admin开始
               'ctr' => $controller, //控制器名称
               'action' => $action, //方法名
               'uri' => trim($uri, '/'), //路由地址
               'method' => strtolower($method), //请求方式
            ];
            $formatRoute['uri_method'] = $formatRoute['uri'] . ':' . $formatRoute['method'];
            $formatRoutes[] = $formatRoute;
        }
        return $formatRoutes;
    }

    //新增或编辑权限
    public function addOrEditAccess($param)
    {
        $id = $param['id'] ?? 0;
        $accessName = $param['access_name'];
        $menuId = $param['menu_id'];
        $sort = $param['sort'] ?? 30000;
        $routeIds = explode(',', $param['route_ids']);

        $exist = app('model_menu')
            ->select('menu_id')
            ->where('menu_id', $menuId)
            ->where('parent_id', '>', 0)
            ->first();
        if (!$exist) throw new BasicException(0, '菜单id错误');

        $exist = app('model_access')
            ->select('id')
            ->where('name', $accessName)
            ->where('menu_id', $menuId)
            ->where(function ($query) use ($id) {
                if ($id > 0) {
                    $query->where('id', '<>', $id);
                }
            })
            ->first();
        if ($exist) throw new BasicException(0, '同一菜单下不能有重复的权限名称');

        if (count($routeIds) != count(array_unique($routeIds))) {
            throw new BasicException(0, '选择了重复的路由');
        }

        $queryRouteIds = app('model_route')->select('id')->whereIn('id', $routeIds)->pluck('id')->toArray();
        if (count($routeIds) != count($queryRouteIds)) {
            throw new BasicException(0, '路由id错误');
        }

        DB::beginTransaction();
        try {

            $accessData = [
                'name' => $accessName,
                'menu_id' => $menuId,
                'sort' => $sort,
                'admin_id' => app('request')->admin_id,
            ];

            if ($id > 0) {

                $exist = app('model_access')->select('id')->where('id', $id)->first();
                if (!$exist) throw new BasicException(0, '权限id错误');

                //查询权限原来绑定的路由
                $originalRouteIds = app('model_access_route_join')->where('access_id', $id)->pluck('route_id')->toArray();
                app('model_access')->where('id', $id)->update($accessData);
            } else {
                $id = app('model_access')->add($accessData);
                $originalRouteIds = [];
            }

            //要新增的权限路由关联
            $insertRouteIds = array_diff($routeIds, $originalRouteIds);
            foreach ($insertRouteIds as $routeId) {
                app('model_access_route_join')->add(['access_id' => $id, 'route_id' => $routeId]);
            }

            //要删除的权限路由关联
            $mvRouteIds = array_diff($originalRouteIds, $routeIds);
            foreach ($mvRouteIds as $routeId) {
                app('model_access_route_join')->where(['access_id' => $id, 'route_id' => $routeId])->delete();
            }

            DB::commit();
            return true;
        } catch (\Exception $e) {
            DB::rollBack();
            throw new BasicException(0, $e->getMessage());
        }
    }

    //获取角色权限路由
    public function getRoleAccessRoutes($roleId)
    {
        return app('model_route')->from('ln_route as r')
            ->select('r.uri', 'method')
            ->leftJoin('ln_access_route_join as arj', 'r.id', '=', 'arj.route_id')
            ->leftJoin('ln_role_access_join as raj', 'arj.access_id', '=', 'raj.access_id')
            ->where('raj.role_id', $roleId)
            ->groupBy('r.id')
            ->get()->toArray();
    }

    //新增或编辑角色
    public function addOrEditRole($param)
    {
        $id = $param['id'] ?? 0;
        $roleName = $param['role_name'];
        $roleDesc = $param['role_desc'] ?? '';
        $status = $param['status'];
        $accessIds = $param['access_ids'] ?? '';

        $exist = app('model_role')
            ->select('role_Id')
            ->where('role_name', $roleName)
            ->where(function ($query) use ($id) {
                if ($id > 0) {
                    $query->where('role_id', '<>', $id);
                }
            })
            ->where('is_delete', 0)
            ->first();
        if ($exist) throw new BasicException(0, '角色名称已经存在');

        if ($accessIds) {
            $accessIds = explode(',', $accessIds);
            $queryAccessCount = app('model_access')->whereIn('id', $accessIds)->count();
            if (count($accessIds) != $queryAccessCount) {
                throw new BasicException(0, '权限id错误');
            }
        } else {
            $accessIds = [];
        }

        DB::beginTransaction();
        try {

            $data = [
                'role_name' => $roleName,
                'role_memo' => $roleDesc,
                'status' => $status,
            ];
            if ($id > 0) {

                $exist = app('model_role')->select('role_id')->where('role_id', $id)->first();
                if (!$exist) throw new BasicException(0, '角色id错误');

                app('model_role')->where('role_id', $id)->update($data);

                //原始权限id
                $originalAccessIds = app('model_role_access_join')
                    ->select('access_id')
                    ->where('role_id', $id)
                    ->pluck('access_id')->toArray();
            } else {

                $data['add_time'] = time();
                $id = app('model_role')->insertGetId($data);

                $originalAccessIds = [];
            }

            //要增加的权限
            $insertAccessIds = array_diff($accessIds, $originalAccessIds);
            foreach ($insertAccessIds as $insertAccessId) {
                app('model_role_access_join')->insert(['role_id' => $id, 'access_id' => $insertAccessId]);
            }
            //要删除的权限
            $delAccessIds = array_diff($originalAccessIds, $accessIds);
            foreach ($delAccessIds as $delAccessId) {
                app('model_role_access_join')->where(['role_id' => $id, 'access_id' => $delAccessId])->delete();
            }

            DB::commit();
            return true;
        } catch (\Exception $e) {
            DB::rollBack();
            throw new BasicException(0, $e->getMessage());
        }
    }

    //获取系统所有菜单
    public function getAllMenus()
    {
        $subMenus = app('model_menu')->getMenus(2);

        $menus = app('model_menu')->getMenus(1);

        //二级菜单追加到一级菜单
        app('model_menu')->subMenuAppend($menus, $subMenus);

        return $menus;
    }

    //删除权限（需要在事务中执行）
    public function delAccesses($accessIds)
    {
        //删除权限
        app('model_access')->whereIn('id', $accessIds)->delete();
        //删除角色与权限的关联
        app('model_role_access_join')->whereIn('access_id', $accessIds)->delete();
        //删除权限与路由的关联
        app('model_access_route_join')->whereIn('access_id', $accessIds)->delete();
    }
}